/*
 * Copyright (c) 2011-2012 Alexander Dubu
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * o  Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * o  Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * o  Neither the name Axil nor the names of its contributors may be used to
 *    endorse or promote products derived from this software without specific
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package axil.compiler;

import axil.compiler.ast.IdentifierNode;

import java.util.ArrayList;
import java.util.List;

import static axil.framework.Functions.nextID;


/**
 * The identifiers that are in scope at this point in the compilation process.
 * Axil is a lexically scoped language, so the scope is dynamic throughout the
 * compilation process.
 */
public class Scope {
	public static final Scope root = new Scope();

	private Scope parent;
	private List<IdentifierNode> idents;


	private Scope() {
		parent = null;
		idents = null;
	}


	public Scope(Scope parent) {
		assert parent != null;
		this.parent = parent;
		this.idents = new ArrayList<IdentifierNode>();
	}


	/**
	 * Return the parent scope of this scope. If this is the root scope, then
	 * we return ourselves as a convenience.
	 */
	public Scope parent() {
		return parent == null ? this : parent;
	}


	public void put(IdentifierNode ident) {
		ident.id(nextID());
		idents.add(ident);
	}


	public boolean defines(IdentifierNode ident) {
		return identifier(ident.identity()) != null;
	}


	public IdentifierNode identifier(String ident) {
		if (idents != null) {
			for (IdentifierNode node : idents) {
				if (node.identity().equals(ident)) {
					return node;
				}
			}
			if (parent != null) {
				return parent.identifier(ident);
			}
		}
		return null;
	}
}
